/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package io.iec.edp.caf.rest;

import io.iec.edp.caf.commons.utils.SpringBeanUtils;
import io.iec.edp.caf.commons.utils.StringUtils;
import io.iec.edp.caf.rest.server.RESTEndpointUtil;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.cxf.Bus;
import org.apache.cxf.endpoint.Server;
import org.springframework.util.Assert;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Rest服务注册器
 * 对外暴露，提供的外界调用的
 * @author guowenchang
 */
@Slf4j
@Deprecated
//todo 被com.inspur.gs.gsp.sys.securitylevel.config.ExternalApiConfiguration依赖，命名空间无法调整
public class RESTServiceRegistrar {
    private static final RESTServiceRegistrar singleton = new RESTServiceRegistrar();

    private Boolean restRegistryFinished = false;

    //rest服务注册表
    private final Map<String, RESTEndpoint> restEndpointMap = new TreeMap<>();

    private final ConcurrentHashMap<String, Server> serverMap = new ConcurrentHashMap<>();

    private final Lock lock = new ReentrantLock();

    private Bus bus = null;

    /**
     * 获取单例对象
     *
     * @return
     */
    public static RESTServiceRegistrar getSingleton() {
        return singleton;
    }

    /**
     * 注册Rest服务
     *
     * @param restEndpoint
     */
    public void registerRestEndpoint(RESTEndpoint restEndpoint) {
        try {
            lock.lock();
            Assert.isTrue(!StringUtils.isEmpty(restEndpoint.getPath()), "path can not be null");
            doRegisterRestEndpoint(restEndpoint);
            if (restRegistryFinished) {
                //直接发布RestEndpoint
                doPublishRestEndpoint(restEndpoint);
            }
        } finally {
            log.info("registerRestEndpoint, restName: "+restEndpoint.getRestServiceName()+", path: "+restEndpoint.getPath());
            lock.unlock();
        }
    }

    @SneakyThrows
    public void publishRestEndpoint(RESTEndpoint restEndpoint){
        doPublishRestEndpoint(restEndpoint);
    }

    /**
     * 发布rest服务
     * @param restEndpoint
     * @throws IllegalAccessException
     * @throws ClassNotFoundException
     * @throws InstantiationException
     */
    private void doPublishRestEndpoint(RESTEndpoint restEndpoint) {
        if (bus == null) {
            bus = SpringBeanUtils.getBean(Bus.class);
        }

        Server server = RESTEndpointUtil.createJAXRSServer(restEndpoint.getPath(), bus, restEndpoint.getServices());
        if(server!=null){
            serverMap.put(restEndpoint.getPath(), server);
        }else{
            log.error("creat cxf server fail, restName: "+restEndpoint.getRestServiceName()+", path: "+restEndpoint.getPath());
        }

        log.info("doPublishRestEndpoint, restName: "+restEndpoint.getRestServiceName()+", path: "+restEndpoint.getPath());
    }

    /**
     * 注册rest服务，不发布
     * 只是把endpoint放到了map里
     * @param restEndpoint
     */
    private void doRegisterRestEndpoint(RESTEndpoint restEndpoint) {
        //如果发布了同一path下的RestEndpoint 这里合并处理
        RESTEndpoint duplicatedRestEndpoint = restEndpointMap.get(restEndpoint.getPath());
        if (duplicatedRestEndpoint == null) {
            restEndpointMap.put(restEndpoint.getPath(), restEndpoint);
        } else {
            log.error("Duplicate RESTEndpoint found: " + restEndpoint.getPath() + getDuplicateDetail(restEndpoint, duplicatedRestEndpoint));
            //duplicatedRestEndpoint.getServices().addAll(restEndpoint.getServices());
            log.info("doRegisterRestEndpoint, restName: "+restEndpoint.getRestServiceName()+", path: "+restEndpoint.getPath());
        }
    }

    private String getDuplicateDetail(RESTEndpoint restEndpoint, RESTEndpoint duplicatedRestEndpoint) {
        Object service1 = restEndpoint.getServices().get(0);
        Object service2 = duplicatedRestEndpoint.getServices().get(0);
        StringBuilder builder = new StringBuilder().append(" in ")
                .append(service1.getClass().getClassLoader().getResource(service1.getClass().getName().replace('.', '/').concat(".class")))
                .append(" and ")
                .append(service2.getClass().getClassLoader().getResource(service2.getClass().getName().replace('.', '/').concat(".class")));
        return builder.toString();
    }

    public void finishRegistry() {
        this.restRegistryFinished = true;
    }

    public Collection<RESTEndpoint> getEndpoints() {
        return restEndpointMap.values();
    }

    public RESTEndpoint findEndpoint(String path) {
        return restEndpointMap.get(path);
    }

    public void putEndpoints(List<RESTEndpoint> endpoints) {
        try {
            lock.lock();
            for (RESTEndpoint restEndpoint : endpoints) {
                doRegisterRestEndpoint(restEndpoint);
            }
        } finally {
            lock.unlock();
        }
    }

    //注销path下的cxf server和endpoint
    public Boolean unregister(String path) {
        try {
            lock.lock();
            Server server = serverMap.get(path);
            if (server == null) {
                return false;
            }

            server.destroy();
            serverMap.remove(path);
            restEndpointMap.remove(path);
            return true;
        } finally {
            lock.unlock();
        }
    }
}
